#include "MemoryPCH.h"
#include "MM_MemoryTracker.h"
#include <assert.h>

using namespace Memory;
using namespace std;
//--------------------------------------------------------------------------
//MM_MemoryTracker
//--------------------------------------------------------------------------
MM_MemoryTracker::MM_MemoryTracker()
: mTotalAllocations(0)
, mTotalOverhead(0)
, m_stCurrentAllocID(0)
, m_stBreakAllocID( INT_MAX )
{

}
//--------------------------------------------------------------------------
MM_MemoryTracker::~MM_MemoryTracker()
{
}
//--------------------------------------------------------------------------
void MM_MemoryTracker::RecordAlloc(void* ptr, size_t sz, uint32_t pool /* = 0 */, 
								   const char* file /* = 0 */, 
								   size_t ln /* = 0 */, 
								   const char* func /* = 0 */)
{
	MM_MemoryAutoLock kLock(&m_kLock);

	AllocationMap::iterator iter = mAllocations.find(ptr);
	if ( iter != mAllocations.end() )
	{
		assert( false && "Double allocation with same address - "
			"this probably means you have a mismatched allocation / deallocation style, "
			"check if you're are using T_ALLOC / T_FREE and T_NEW_E / T_DELETE_E consistently");
	}
		
	assert( m_stCurrentAllocID != m_stBreakAllocID );
	
	mAllocations[ptr] = Alloc(sz, pool, file, ln, func,m_stCurrentAllocID++);

	mAllocationsByPool[pool] += sz;

	mTotalAllocations += sz;
	mTotalOverhead += sizeof(Alloc);
}
//--------------------------------------------------------------------------
void MM_MemoryTracker::RecordDealloc(void* ptr)
{
	MM_MemoryAutoLock kLock(&m_kLock);

	// deal cleanly with null pointers
	if (!ptr)
		return;

	AllocationMap::iterator Iter = mAllocations.find(ptr);
	assert(Iter != mAllocations.end() && "Unable to locate allocation unit - "
		"this probably means you have a mismatched allocation / deallocation style, "
		"check if you're are using T_ALLOC / T_FREE and T_NEW_E / T_DELETE_E consistently");

	// update category stats
	mAllocationsByPool[Iter->second.pool] -= Iter->second.bytes;
	
	// global stats
	mTotalAllocations -= Iter->second.bytes;
	
	mAllocations.erase(Iter);
	
	mTotalOverhead -= sizeof(Alloc);
}
//--------------------------------------------------------------------------
StringType MM_MemoryTracker::DumpMemoryStats()
{
	StringStreamType kStrStream;

	if (mAllocations.empty())
	{
		kStrStream << "NULL";
	}
	else
	{
		size_t totalMem = 0;
		
		for (AllocationMap::const_iterator i = mAllocations.begin(); i != mAllocations.end(); ++i)
		{
			/*
			-"format=%(%F(%l):%) error %n: (%t -- %m)"     //  Messages will contain
			//  file information (%F), the line number (%l), the
			//  message number (%n), message type (%t) and message text (%m).
			*/
			const Alloc& alloc = i->second;
			if (alloc.filename)
				kStrStream << alloc.filename << "(" << alloc.line << ")"<<": " << alloc.function << " alloc id:"<<alloc.alloc_no<<" , ";
			else
				kStrStream << "(unknown source): ";
			
			kStrStream << alloc.bytes << " bytes";
			kStrStream << std::endl;
			
			totalMem += alloc.bytes;
		}

		kStrStream << std::endl;
		kStrStream << mAllocations.size() << " allocate," << totalMem << " bytes total,"<<(totalMem>>20)<<" MB total";
	}
	
	return kStrStream.str();
}




